import * as fs from 'fs'
import qiniu from 'qiniu'

class QiNiu {
    private _bucket: any

    private _domain: any

    private _config: any

    private _mac: any

    private formUploader: any

    private _bucketManager: any

    constructor({ bucket, accessKey, secretKey, domain }) {
        this._domain = domain
        this._bucket = bucket
        const config: any = new qiniu.conf.Config()
        config.zone = qiniu.zone.Zone_z0
        this._config = config
        this._mac = new qiniu.auth.digest.Mac(accessKey, secretKey)
        this._bucketManager = new qiniu.rs.BucketManager(this._mac, this._config)
    }

    getToken(options) {
        options = { scope: this._bucket, ...options }

        const putPolicy = new qiniu.rs.PutPolicy(options)
        return putPolicy.uploadToken(this._mac)
    }

    getExtra(options = {}) {
        const extra = new qiniu.form_up.PutExtra()

        Object.keys(options || {}).forEach((key) => {
            extra[key] = options[key]
        })

        return extra
    }

    putFile(id: string, remotePath, localFilePath, options = {}, cb: (id: string, progress: number) => void) {
        const extra = this.getExtra(options)
        const token = this.getToken({
            scope: `${this._bucket}:${remotePath}`
        })
        const totalLength = fs.statSync(localFilePath).size
        const putExtra = new qiniu.resume_up.PutExtra('', {}, '', '', (data) => {
            const progress = Math.ceil((data / totalLength) * 100)
            cb(id, progress)
        })
        const formUploader = new qiniu.resume_up.ResumeUploader(this._config)

        return new Promise((resolve, reject) => {
            let count = 0
            const upload = async () => {
                if (count > 0) {
                    console.log(`${remotePath}上传失败，正在重试第${count}次上传======`)
                }
                formUploader.putFile(token, remotePath, localFilePath, putExtra, (err: any, resBody, resInfo) => {
                    if (err) {
                        if (typeof err === 'object' && err.status === -1) {
                            count++
                            if (count > 5) {
                                console.log(`${remotePath}重试上传失败，共${count - 1}次`)
                                reject(err)
                            } else {
                                upload()
                            }
                        } else {
                            reject(err)
                        }
                        return
                    }

                    if (resInfo.statusCode === 200) {
                        resolve(resBody)
                    } else {
                        reject(new Error(resBody.error))
                    }
                })
            }
            upload()
        })
    }

    put(remotePath, text, options = {}) {
        const extra = this.getExtra(options)
        const token = this.getToken({
            scope: `${this._bucket}:${remotePath}`
        })

        const formUploader = new qiniu.form_up.FormUploader(this._config)

        return new Promise((resolve, reject) => {
            formUploader.put(token, remotePath, text, extra, (err, resBody, resInfo) => {
                if (err) {
                    return reject(err)
                }

                if (resInfo.statusCode === 200) {
                    resolve(resBody)
                } else {
                    // reject({
                    //     code: resInfo.statusCode,
                    //     data: resBody
                    // })
                }
            })
        })
    }

    batchDelete(keys = [] as any) {
        keys = keys.map((key, index) => qiniu.rs.deleteOp(this._bucket, key))

        return new Promise((resolve, reject) => {
            this._bucketManager.batch(keys, (err, resBody, resInfo) => {
                // console.log(resInfo, resInfo.statusCode, err, 'batchDelete===')
                if (err) {
                    return reject(err)
                }
                if (resInfo.statusCode === 200 || resInfo.statusCode === 298) {
                    resolve({
                        code: resInfo.statusCode,
                        data: resBody
                    })
                } else {
                    // reject({
                    //     code: resInfo.statusCode,
                    //     data: resBody
                    // })
                }
            })
        })
    }

    getPublicDownloadUrl(remotePath) {
        const publicDownloadUrl = this._bucketManager.publicDownloadUrl(this._domain, remotePath)
        return publicDownloadUrl
    }
}

export default QiNiu
